/**
 * XML Conditional Functional Dependence
 * ----------------------------------------------------------------
 * 
 * This class represents a conditional functional dependence XML with the
 * transformation of path expressions in Finite automata. Thus we have:
 * 
 * xdf = (M, C, (T'-> T"))
 * 
 * where: M is the context path; C is the conditional path; T' is source path or
 * left side; T" is destination path or right side;
 * 
 * @author Eder P. C. Flor
 * @author Aryadne Guardieiro P. Rezende
 */
package model.constraints;

import java.util.Iterator;
import java.util.StringTokenizer;

import model.util.ExpressionSet;
import model.util.MathExpression;

import automata.Alphabet;
import automata.Fsa;
import automata.Label;
import automata.State;
import automata.StateSet;
import automata.Transitions;

public class XDFC extends AbstractConstraint {

	private static final long serialVersionUID = 1L;
	
	private Fsa conditional = new Fsa();
	private String condExpr;
	private ExpressionSet expressionSet = new ExpressionSet();
	
	public XDFC() { }
	
	public XDFC(String name, Fsa f1, Fsa f2, Fsa f3, Fsa f4) {
		nameConstraint = name;
		contextFsa = f1;
		sourceFsa = f2;
		targetFsa = f3;
		conditional = f4;
	}

	/*public void setExpressions(State s, String v)
	{
		double value2 = Double.parseDouble(v);
		Expression e = new Expression()
	}*/
	
	public Fsa pathToFsaCond(String path) throws Exception {
		// System.out.println("Path To FSA: " + path);
		Fsa f = new Fsa();
		int exp = 1;
		int i = 1;
		Label star = new Label("*");
		State start = new State(1); // initial state
		State sant; // previous state
		State s; // ??
		Alphabet alpha = new Alphabet(); // alphabet of Cond
		StateSet ss = new StateSet(); // Set of initial stats?!!!
		StateSet fs = new StateSet(); // Set of final stats
		Transitions t = new Transitions(); // transitions of FSA
		String token = new String();
		MathExpression mathExpression = new MathExpression();
		boolean operatorFlag = false; // is true if the anterior simbol is a aritmetic operator
		ss.add(start); // add the initial stat in the set
		sant = start; // the first state will be the anterior state of all the next starts
		StringTokenizer st = new StringTokenizer(path, " "); // the string path will be broken

		Exception sintaxErrorException = new Exception("Error on syntax of conditions. Check, please."); 

		while (st.hasMoreTokens()){ // while exist space in the string path		
			token = st.nextToken(); // token will be the label of XML document

			if (mathExpression.isMathOperator(token)) {//checks of operator 
				//mathOperators.add(token);
				//mathExp++;// number of math expressions increases
				mathExpression.setOperator(token);
				operatorFlag = true;
			} else {

				if (token.equals("or") || token.equals("and")) {
					if (!mathExpression.setLinkOperator(token)) {
						throw sintaxErrorException;
					} else {
						expressionSet.addExpression(sant, mathExpression); // add a expression referent of the current state
					}
						
					//logicExp++; // number of logic expressions increases
					//operatorFlag = true;
				} else {
					if (token.equals("//"))// indicates that anything can be
											// between the previous state and
											// the next state - star transition
					{
						alpha.add(star);
						StateSet ss2 = new StateSet();
						ss2.add(sant);
						t.put(sant, star, ss2);
					} else if (operatorFlag) // if the antSimbol is a operator
												// the current simbol is a
												// constant
					{
						mathExpression.setConstant(token);//add a constant in to the expression
					} else { // then, the token is a label					
						
						Label l = new Label(token);
						
						if (alpha.contains(l)) {
							sant = new State(sant.elt + 1); // one new state is created
						} else {
							i++;
							alpha.add(l);
							s = new State(i);
							ss.add(s);
							StateSet ss1 = new StateSet();
							ss1.add(s);
							t.put(sant, l, ss1);
							sant = s;
						}
					}
					operatorFlag = false;
				}
			}
		}

		fs.add(sant);
		f.set_alphabet(alpha);
		f.set_states(ss);
		f.set_start_state(start);
		f.set_final_states(fs);
		f.set_transitions(t);

		return f;
	}

	/**
	 * Function that creates a path from the source FSA And there you have the token |
	 * @param s
	 * @return void, but set new source
	 */
	public void setSourceFsa(String s) {
		leftPath = new String(s);
		sourceFsa = pathToFsa(s);
		StringTokenizer st = new StringTokenizer(s, " ");
		String token = new String();

		while (st.hasMoreTokens()) {
			token = st.nextToken();
			
			if (token.equals("|")) 
				npaths++;			
		}
		setJ();
	}

	/**
	 * Function that creates FSA (automaton) from a path
	 * @param path
	 * @return new FSA
	 */
	public Fsa getConditional() {
		return conditional;
	}

	public void setConditional(String conditional) throws Exception {
		condExpr = new String(conditional);	
		this.conditional = pathToFsaCond(conditional);
	}

	/**
	 * A patir de um FSA sabe qual tipo contextFsa, sourceFsa or targetFsa
	 * @param Object FSA
	 * @return integer 1 is contextFSA, 2 source FSA or 3 targetFSA
	 */
	public int getFsaPosition(Fsa f) {
		if (f == contextFsa) 
			return 1;
		if (f == sourceFsa)
			return 2;
		if (f == targetFsa)
			return 3;		
		if (f == conditional)
			return 4;
		else
			return 0;
	}

	public void setNPaths(int n) {
		npaths = n;
	}

	public void setJ() {
		Iterator<State> i = sourceFsa.get_final_states().iterator();

		while (i.hasNext())
			j.add(i.next().elt);	
	}

	public int getJ(Integer state) {
		return j.indexOf(state);
	}

	public void setCondExpr(String condExpr) {
		this.condExpr = condExpr;
	}

	public String getCondExpr() {
		return condExpr;
	}	
	
	public String toString() {
		String str = new String();
		str = "<b>XDFC Name: </b>" + nameConstraint + "<br><br>";
		str += "<b>Fsa Context: </b>" + contextFsa.toStringWeb() + "<br>";
		str += "<b>Fsa Source: </b>" + sourceFsa.toStringWeb() + "<br>";
		str += "<b>Fsa Target: </b>" + targetFsa.toStringWeb() + "<br>";
		str += "<b>Fsa Conditional: </b>" + conditional.toStringWeb() + "<br>";
		str += "<b>Paths: </b>" + npaths + "<br>";
		return str;
	}
	
	public String toStringPath() {
		String str = new String();
		str += "<b>XDFC Name:</b> " + nameConstraint + "<br><br>";
		str += "<b>Constraint name:</b> " + context + "<br><br>";
		str += "<b>Left Path:</b> " + leftPath +  "<br><br>";
		str += "<b>Type of equality Left:</b> " + leftValue + "<br><br>";
		str += "<b>Right Path:</b> " + rightPath +  "<br><br>";
		str += "<b>Conditional: </b>" + condExpr + "<br>";
		
		if(rightValue == 0)
			str += "<b>Type of equality Right:</b> Value<br>";
		else
			str += "<b>Type of equality Right:</b> Node<br>";
		
		return str;
	}	   	
}